Skip to content

Conversation

@zeitlinger
Copy link
Member

@zeitlinger zeitlinger commented Jun 18, 2025

Fixes #14048

@zeitlinger zeitlinger self-assigned this Jun 18, 2025
@github-actions github-actions bot added the test native This label can be applied to PRs to trigger them to run native tests label Jun 18, 2025
@otelbot-java-instrumentation
Copy link
Contributor

🔧 The result from spotlessApply was committed to the PR branch.

@zeitlinger zeitlinger marked this pull request as ready for review June 19, 2025 16:09
@zeitlinger zeitlinger requested a review from a team as a code owner June 19, 2025 16:09
@zeitlinger zeitlinger force-pushed the spring-starter-declarative-config branch 2 times, most recently from 17d949a to f81444f Compare June 19, 2025 16:57
@zeitlinger
Copy link
Member Author

@laurit can you help me figure out what the problem is?

AgentInstrumentationTest > classPathSetUp() FAILED	
    java.lang.NoClassDefFoundError: io/opentelemetry/sdk/autoconfigure/spi/ConfigProperties	
        at java.lang.Class.forName0(Native Method)	
        at java.lang.Class.forName(Class.java:348)	
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:328)	
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)	
        at java.lang.Class.forName0(Native Method)	
        at java.lang.Class.forName(Class.java:264)	
        at instrumentation.AgentInstrumentationTest.classPathSetUp(AgentInstrumentationTest.java:53)

@zeitlinger
Copy link
Member Author

@laurit can you help me figure out what the problem is?

AgentInstrumentationTest > classPathSetUp() FAILED	
    java.lang.NoClassDefFoundError: io/opentelemetry/sdk/autoconfigure/spi/ConfigProperties	
        at java.lang.Class.forName0(Native Method)	
        at java.lang.Class.forName(Class.java:348)	
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:328)	
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)	
        at java.lang.Class.forName0(Native Method)	
        at java.lang.Class.forName(Class.java:264)	
        at instrumentation.AgentInstrumentationTest.classPathSetUp(AgentInstrumentationTest.java:53)

tried to fix that with cbb070b

@laurit
Copy link
Contributor

laurit commented Jun 20, 2025

@laurit can you help me figure out what the problem is?

AgentInstrumentationTest > classPathSetUp() FAILED	
    java.lang.NoClassDefFoundError: io/opentelemetry/sdk/autoconfigure/spi/ConfigProperties	
        at java.lang.Class.forName0(Native Method)	
        at java.lang.Class.forName(Class.java:348)	
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:328)	
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)	
        at java.lang.Class.forName0(Native Method)	
        at java.lang.Class.forName(Class.java:264)	
        at instrumentation.AgentInstrumentationTest.classPathSetUp(AgentInstrumentationTest.java:53)

tried to fix that with cbb070b

DeclarativeConfigPropertiesBridge is in boot loader but it depends on io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties that is not in boot loader

@zeitlinger
Copy link
Member Author

DeclarativeConfigPropertiesBridge is in boot loader but it depends on io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties that is not in boot loader

I can't figure out what change could have caused that.

Is the solution to not used ConfigProperties in the agent config?

@zeitlinger
Copy link
Member Author

DeclarativeConfigPropertiesBridge is in boot loader but it depends on io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties that is not in boot loader

I can't figure out what change could have caused that.

Is the solution to not used ConfigProperties in the agent config?

Let's see if it's 7116de1

@laurit
Copy link
Contributor

laurit commented Jun 20, 2025

Let's see if it's 7116de1

I don't think this is going to help. javaagent-extension-api belongs to boot loader, any class you are going to use there also needs to be in boot loader. Since based on that DeclarativeConfigPropertiesBridge needs to be in boot loader, it implements io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties that is not in boot loader, and shouldn't be there. Based on that I'd say the design is broken and needs to be rethought.

@zeitlinger
Copy link
Member Author

Let's see if it's 7116de1

I don't think this is going to help. javaagent-extension-api belongs to boot loader, any class you are going to use there also needs to be in boot loader. Since based on that DeclarativeConfigPropertiesBridge needs to be in boot loader, it implements io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties that is not in boot loader, and shouldn't be there. Based on that I'd say the design is broken and needs to be rethought.

Why is it not failing on main? DeclarativeConfigPropertiesBridge is not changed (unless I miss something)

@laurit
Copy link
Contributor

laurit commented Jun 20, 2025

Why is it not failing on main? DeclarativeConfigPropertiesBridge is not changed (unless I miss something)

Because on main you don't have it in boot loader. Actually I was wrong about javaagent-extension-api belonging to boot loader. During agent packaging some of it is moved to boot loader and other parts are moved to agent loader. See

bootstrapLibs(project(":javaagent-extension-api")) {
and
// exclude the agent part of the javaagent-extension-api; these classes will be added in relocate tasks
and
// exclude the bootstrap part of the javaagent-extension-api
I'd try excluding the bridge in
exclude("io.opentelemetry", "opentelemetry-sdk-extension-autoconfigure-spi")

@zeitlinger
Copy link
Member Author

I'd try excluding the bridge in

exclude("io.opentelemetry", "opentelemetry-sdk-extension-autoconfigure-spi")

That worked - thanks a lot!

@zeitlinger zeitlinger marked this pull request as draft June 25, 2025 07:07
@zeitlinger zeitlinger force-pushed the spring-starter-declarative-config branch from bf6b7f8 to 9427fe6 Compare June 30, 2025 09:31
@otelbot-java-instrumentation
Copy link
Contributor

🔧 The result from spotlessApply was committed to the PR branch.

@zeitlinger zeitlinger marked this pull request as ready for review June 30, 2025 10:42
@zeitlinger zeitlinger marked this pull request as draft June 30, 2025 10:48
@zeitlinger zeitlinger moved this from Blocked to In Progress in Declarative Configuration: Java Jul 4, 2025
@zeitlinger zeitlinger force-pushed the spring-starter-declarative-config branch from 482c0be to 5fcca3f Compare July 7, 2025 12:56
@zeitlinger zeitlinger force-pushed the spring-starter-declarative-config branch from a011497 to d803eb5 Compare November 8, 2025 11:02
return false;
}

private static boolean isPrimitive(Object object) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since String is not primitive the name is slightly misleading. Perhaps something like isSimple would be a better fit.
Also it does not list all the primitive types.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 70 to 78
static ObjectMapper getObjectMapper() {
try {
Field field = DeclarativeConfiguration.class.getDeclaredField("MAPPER");
field.setAccessible(true);
return (ObjectMapper) field.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new DeclarativeConfigException("Failed to access ObjectMapper", e);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the reflection worth it? Any reason you wish to avoid creating the ObjectMapper instance yourself? Since the MAPPER is package private could also consider adding a class in the same package for reading that field.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason

I want to make sure the config options don't diverge

  static final ObjectMapper MAPPER;

  static {
    MAPPER =
        new ObjectMapper()
            // Create empty object instances for keys which are present but have null values
            .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
    // Boxed primitives which are present but have null values should be set to null, rather than
    // empty instances
    MAPPER.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
    MAPPER.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
    MAPPER.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
    MAPPER.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
  }

.. package protected

good idea - changed

Comment on lines 113 to 116
// Ensure the list is large enough
while (list.size() <= index) {
list.add(null);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArrayList has ensureCapacity method that might simplify this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, this doesn't work, as ensureCapacity doesn't set the size

@zeitlinger
Copy link
Member Author

@laurit thanks for the review! please check again 😄

@zeitlinger zeitlinger requested a review from laurit November 11, 2025 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test native This label can be applied to PRs to trigger them to run native tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support declarative config for spring starter

3 participants